package com.hiup.web;

import com.djhu.hiup.documentum.client.DocumentService;
import com.hiup.config.comment.CustomDomainComment;
import com.hiup.config.comment.InterComment;
import com.hiup.config.comment.RecordComment;
import com.hiup.config.comment.RemoteComment;
import com.hiup.constant.*;
import com.hiup.entity.PatientVisit;
import com.hiup.entity.Person;
import com.hiup.entity.TblRemoteConsult;
import com.hiup.service.TblRemoteConsultService;
import com.hiup.service.impl.PatientVisitServiceImpl;
import com.hiup.service.impl.PersonServiceImpl;
import com.hiup.utils.BeanUtil;
import com.hiup.utils.FileUtils;
import com.hiup.utils.HttpUtils;
import com.hiup.utils.JSONUtil;
import com.hiup.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.validation.Valid;
import java.io.File;
import java.util.*;

/**
 * 远程会诊controller
 *
 * @author YFC
 * @create 2018-12-20 上午 2:53
 */
@RestController
@RequestMapping("/patient")
@Api(tags = "远程会诊接口程序")
public class RemoteController {
    private static final Logger log = LoggerFactory.getLogger(RemoteController.class);

    /**
     * 递归次数，查询患者时避免进入死循环
     */
    private static int recursionLength = 0;


    @Autowired
    private TblRemoteConsultService consultService;
    @Autowired
    private PersonServiceImpl personService;
    @Autowired
    private PatientVisitServiceImpl patientVisitService;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RemoteComment remoteComment;
    @Autowired
    private Environment environment;
    @Autowired
    private InterComment interComment;
    @Autowired
    private RecordComment recordComment;
    @Autowired
    private CustomDomainComment customDomainComment;
    @Autowired
    private DocumentService documentService;

    /**
     * 存储提醒服务参数
     * 推送患者基本信息到指定接口
     * 推送患者病例文书到指定接口
     *
     * @param consult 提醒服务对象
     * @param result  验证参数
     * @return
     */
    @ResponseBody
    @ApiOperation(value = "提醒服务")
    @RequestMapping(value = "/remind", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    public ResponseBean saveRemind(@RequestBody @Valid TblRemoteConsult consult, BindingResult result) {
        log.debug("提醒服务传入的请求参数为 {}", JSONUtil.objectToJson(consult));
        log.info("提醒服务传入的请求参数为 {}", JSONUtil.objectToJson(consult));

        if (result.hasErrors()) {
            log.debug("参数错误，需要验证");
            return ResponseBean.error(result.getFieldError().getDefaultMessage());
        }

        consultService.insert(consult);
        return pushInfoToRemote(consult);
    }

    @ResponseBody
    @GetMapping(value = "/get", produces = "application/json;charset=utf-8")
    public ResponseBean get() {
        log.info("get.......");
        return ResponseBean.ok();
    }


    /**
     * 推送患者信息&病历信息到远程会诊
     *
     * @param consult
     * @return
     */
    public ResponseBean pushInfoToRemote(TblRemoteConsult consult) {
        String patientInfoUrl = interComment.getPatientInfoUrl();
        PatientInfoVo patientInfoVo = getPatientInfo(consult);
        ResponseBean responseBean = doPush(patientInfoUrl, patientInfoVo);
        if (!responseBean.isIsSuccess()) {
            return ResponseBean.error();
        }
        String patientFileUrl = interComment.getPatientFileUrl();
        PatientDocumentVo patientDocumentVo = getPatientDocument(consult, patientInfoVo);
        return doPush(patientFileUrl, patientDocumentVo);
    }

    /**
     * 获取患者基本信息
     *
     * @param consult 提醒服务对象
     * @return
     */
    public PatientInfoVo getPatientInfo(TblRemoteConsult consult) {
        log.debug("患者基本信息参数: {}", JSONUtil.objectToJson(consult));
        PatientInfo patientInfo = new PatientInfo();
        patientInfo.setAccessToken(consult.getAccessToken());
        patientInfo.setIdentity_num(consult.getIdentityId());
        patientInfo.setOrg_code(consult.getHospitalId());
        patientInfo.setOrg_name(consult.getHospitalName());
        patientInfo.setSys_type(remoteComment.getSysType());
        Person person = getPerson(consult);
        patientInfo.setPatient_id(person.getCustom10());
        patientInfo.setPatient_name(person.getName());
        PatientInfoVo infoVo = BeanUtil.fromObjSetClazz(PatientInfoVo.class, patientInfo);
        infoVo.setPatient_sex(GlobalConstant.getSex(person.getGenderCd()));
        infoVo.setIdentity_type_code(person.getCertificatesType());
        infoVo.setHome_place(person.getHomeAddress());
        infoVo.setPatient_phone_num(person.getPhoneNumber());
        infoVo.setPatientInfo(patientInfo);
        infoVo.setPerson(person);
        log.debug("患者基本信息为: {}", JSONUtil.objectToJson(infoVo));
        log.info("患者基本信息为: {}", JSONUtil.objectToJson(infoVo));
        return infoVo;
    }

    /**
     * 获取person
     *
     * @param consult
     * @return
     */
    public Person getPerson(TblRemoteConsult consult) {
        String domainId = null;
        String[] multiArray = null;
        if (customDomainComment.isEnabled()) {
            domainId = customDomainComment.getDomain();
        } else {
            multiArray = environment.getProperty(consult.getHospitalId()).split("&");
            if (recursionLength < multiArray.length) {
                domainId = multiArray[recursionLength];
                recursionLength++;
            }
        }
        Person person = getDomainPerson(domainId, consult);
        if (Objects.isNull(person) && !customDomainComment.isEnabled()
                && recursionLength < multiArray.length) {
            getPerson(consult);
        }
        log.debug("获取的person对象为: {}", JSONUtil.objectToJson(person));
        log.info("获取的person对象为: {}", JSONUtil.objectToJson(person));
        return person;
    }


    private Person getDomainPerson(String domainId, TblRemoteConsult consult) {
        log.info("配置的医院域id是: {}", domainId);
        if (Objects.isNull(domainId)) {
            log.info("请配置医院域id.");
            return new Person();
        }
        Map<String, Object> map = new HashMap<>();
        map.put("identity_no", consult.getIdentityId());
        map.put("custom11", domainId);
        log.info("查询person对象的参数为: {}", JSONUtil.objectToJson(map));
        return personService.selectOne(map);
    }

    public static void main(String[] args) {
        String[] array = new String[]{"abc", "abc"};
        System.out.println(array.length);

    }

    /**
     * 获取病历信息
     *
     * @param consult       提醒服务对象
     * @param patientInfoVo
     * @return
     */
    public PatientDocumentVo getPatientDocument(TblRemoteConsult consult, PatientInfoVo patientInfoVo) {
        log.debug("病历信息参数: {},{}", consult, patientInfoVo);
        log.info("病历信息参数: {},{}", consult, patientInfoVo);
        PatientInfo patientInfo = patientInfoVo.getPatientInfo();
        PatientDocumentVo patientDocumentVo = BeanUtil.fromObjSetClazz(PatientDocumentVo.class, patientInfo);
        patientDocumentVo.setPatientInfo(patientInfo);
        Person person;
        if (Objects.isNull(patientInfoVo.getPerson())) {
            person = getPerson(consult);
        } else {
            person = patientInfoVo.getPerson();
        }
        Map<String, String> inhosMap = getInhosNoAndFlowId(person);
        patientDocumentVo.setInhos_no(inhosMap.get(PathologyDataConstant.INHOS_NO));
        patientDocumentVo.setHis_flow_id(inhosMap.get(PathologyDataConstant.HIS_FLOW_ID));
        PatientVisit patientVisit = patientVisitService.selectOne(person.getPersonId());
        patientDocumentVo.setInhos_type(Integer.parseInt(patientVisit.getPatientClass()));
        patientDocumentVo.setMedicalRecords(getImageVo(person).getStudyList());
        setPatientDocumentData(patientDocumentVo, person);
        log.debug("病历信息内容是: {}", JSONUtil.objectToJson(patientDocumentVo));
        log.info("病历信息内容是: {}", JSONUtil.objectToJson(patientDocumentVo));
        return patientDocumentVo;
    }

    /**
     * 获取病例文书的就诊号和流水号
     *
     * @param person
     * @return
     */
    public Map<String, String> getInhosNoAndFlowId(Person person) {
        Map<String, String> map = new HashMap();
        String custom15 = person.getCustom15();
        String inhosNo = null;
        String hisFlowId = null;
        if (!StringUtils.isEmpty(custom15)) {
            String[] inhosArray = custom15.split(GlobalConstant.SPLIT_DOMAIN);
            inhosNo = inhosArray[0];
            hisFlowId = inhosArray[inhosArray.length - 1];
        }
        map.put(PathologyDataConstant.INHOS_NO, inhosNo);
        map.put(PathologyDataConstant.HIS_FLOW_ID, hisFlowId);
        return map;
    }

    /**
     * 获取主数据
     *
     * @param person
     * @return
     */
    private void setPatientDocumentData(PatientDocumentVo patientDocumentVo, Person person) {
        Map<String, Object> pathologyParams = getPathologyParams(person);
        String pathologyData = "";
        try {
            pathologyData = restTemplate.postForObject(interComment.getPathologyUrl(), pathologyParams, String.class);
        } catch (RestClientException e) {
            log.error("调用主数据接口失败!!! {},{}", e.getMessage(), e);
        }
        try {
            dealPathologyData(pathologyData, patientDocumentVo);
        } catch (Exception e) {
            log.error("处理主数据异常,异常原因是: {},{}", e.getMessage(), e);
            return;
        }
    }

    /**
     * 处理主数据获取 临床诊断/ 主诉 / 现病史 / 既往史 / 病理诊断 / 文件对象
     *
     * @param recordData        查询es 得到的主数据 json 格式
     * @param patientDocumentVo 病历文书对象
     */
    private void dealPathologyData(String recordData, PatientDocumentVo patientDocumentVo) {
        log.info("主数据内容: {}", recordData);
        if (StringUtils.isEmpty(recordData)) {
            return;
        }

        JSONObject pathologyData = JSONObject.fromObject(recordData);
        if (!Objects.equals(GlobalConstant.PATHOLOGY_RESULT_CODE, pathologyData.getInt(PathologyDataConstant.CODE))) {
            log.info("获取主数据失败,code是: {}", pathologyData.getInt(PathologyDataConstant.CODE));
            return;
        }

        JSONObject result = pathologyData.getJSONObject(PathologyDataConstant.RESULT);
        JSONArray searchResponses = result.getJSONArray(PathologyDataConstant.SEARCH_RESPONSES);
        for (Object response : searchResponses) {
            JSONArray disposeData = JSONObject.fromObject(response).getJSONArray(PathologyDataConstant.RESULT_DATA);
            JSONObject jsonData = getDataByCreateTime(disposeData);
            String type = JSONUtil.getValue(PathologyDataConstant.PAY_LOAD_TYPE, jsonData);
            int payLoadType = PayLoadTypeConstant.getKey(type);
            String fileMetaList = JSONUtil.getValue(PathologyDataConstant.FILE_META_LIST, jsonData);
            String docName = JSONUtil.getValue(PathologyDataConstant.DOC_NAME, jsonData);
            // 设置文件
            if (StringUtils.isEmpty(fileMetaList)) {
                patientDocumentVo.setPatientFiles(Collections.emptyList());
            } else {
                setPatientFile(fileMetaList, patientDocumentVo, payLoadType, docName);
            }
            // 设置病理数据
            if (payLoadType == PayLoadTypeConstant.DEFAULT_RECORD) {
                setPathologyData(patientDocumentVo);
            }
            // 取临床诊断先后顺序 最后诊断 - 门诊诊断 - 住院诊断
            patientDocumentVo.setClinical_diagnosis(PathologyDataConstant.getDiagnosis(jsonData));
            patientDocumentVo.setChief_complaint(JSONUtil.getValue(PathologyDataConstant.DJ_CAS_DE04, jsonData));
            patientDocumentVo.setPast_history(JSONUtil.getValue(PathologyDataConstant.PAST_HISTORY, jsonData));
            patientDocumentVo.setHistory_of_presentillness(JSONUtil.getValue(PathologyDataConstant.HISTORY_OF_PRESENT_ILLNESS, jsonData));
        }
    }

    /**
     * 获取创建时间最近的一个病历文书对象
     *
     * @param disposeData
     * @return
     */
    private JSONObject getDataByCreateTime(JSONArray disposeData) {
        JSONObject pathologyData = null;
        Long maxTime = 0L;
        for (Object data : disposeData) {
            JSONObject jsonData = JSONObject.fromObject(data);
            String personInfoField = JSONUtil.getValue(PathologyDataConstant.PERSON_INFO_FIELD, jsonData);
            if (!StringUtils.isEmpty(personInfoField)) {
                JSONObject personInfo = JSONObject.fromObject(personInfoField);
                String dateCreated = JSONUtil.getValue(PathologyDataConstant.DATE_CREATED, personInfo);
                if (!StringUtils.isEmpty(dateCreated)) {
                    long created = Long.parseLong(dateCreated);
                    if (created < maxTime) {
                        continue;
                    }
                    maxTime = created;
                }
            }
            pathologyData = jsonData;
        }
        return pathologyData;
    }

    /**
     * 设置病理数据
     *
     * @param patientDocumentVo
     */
    private void setPathologyData(PatientDocumentVo patientDocumentVo) {
        // TODO 设置病理数据 暂时设置为空，因为没有病理数据 2018.12.26
        return;
    }

    /**
     * 设置文件内容
     *
     * @param fileMetaList
     * @param patientDocumentVo
     * @param payLoadType
     */
    private void setPatientFile(String fileMetaList, PatientDocumentVo patientDocumentVo, int payLoadType, String docName) {
        JSONArray files = JSONArray.fromObject(fileMetaList);
        List<PatientFileDataVo> fileList = new ArrayList<>();
        for (Object obj : files) {
            JSONObject file = JSONObject.fromObject(obj);
            PatientFileDataVo fileVo = new PatientFileDataVo();
            String fileUid = JSONUtil.getValue(PathologyDataConstant.FILE_UID, file);
            fileVo.setFileID(fileUid);
            fileVo.setFileCategory(payLoadType);
            fileVo.setFileName(docName);
            // TODO 文件扩展名是不是从配置文件中获取的
            fileVo.setFileExtension(GlobalConstant.FILE_EXTENSION);
            fileVo.setFileData(getFileData(fileUid));
            fileList.add(fileVo);
        }
        patientDocumentVo.setPatientFiles(fileList);
    }

    /**
     * 获取文件二进制流
     *
     * @param fileUid 文件id
     * @return
     */
    private String getFileData(String fileUid) {
        String base64String = "";
        try {
            File file = documentService.download(fileUid);
            log.info("file id is {}, file is {}", fileUid, file);
            if (file != null) {
                String pdfBinary = FileUtils.getPDFBinary(file);
                if (!Objects.isNull(pdfBinary)) {
                    base64String = FileUtils.getPDFBinary(file);
                }
            }
        } catch (Exception e) {
            log.error("download file error!!! {}", e.getMessage(), e);
            log.info("download file error!!!{}", e.getMessage());
            return base64String;
        }
        return base64String;
    }

    /**
     * 调用影像接口返回VO实体
     *
     * @param person
     * @return
     */
    public ImageVo getImageVo(Person person) {
        // 调影像接口
        String imageUrl = interComment.getImageUrl();
        log.info("影像接口地址: {}", imageUrl);
        String empi = person.getEmpi();
        String patientDomainId = person.getCustom11();
        Map<String, Object> map = new HashMap<>();
        map.put(ImageConstant.IMAGE_EMPI, empi);
        map.put(ImageConstant.IMAGE_PATIENT_DOMAIN_ID, patientDomainId);
        log.debug("影像接口参数empi: {},patientDomainId: {}", empi, patientDomainId);
        log.info("影像接口参数empi: {},patientDomainId: {}", empi, patientDomainId);
        ImageVo imageVo;
        try {
            String image = HttpUtils.doHttpGet(imageUrl, GlobalConstant.IS_IMAGE_URL, map.toString());
            if (!StringUtils.isEmpty(image)) {
                imageVo = JSONUtil.jsonToPojo(image, ImageVo.class);
            } else {
                imageVo = new ImageVo();
            }
        } catch (Exception e) {
            log.info("调用影像接口数据失败!!! {}", e.getMessage());
            log.error("调用影像接口数据失败!!! {}", e.getMessage(), e);
            return new ImageVo();
        }
        log.debug("影像接口结果: {}", JSONUtil.objectToJson(imageVo));
        log.info("影像接口结果: {}", JSONUtil.objectToJson(imageVo));
        return imageVo;
    }

    /**
     * 获取病例数据参数
     *
     * @param person
     * @return
     */
    public Map<String, Object> getPathologyParams(Person person) {
        // 主数据中要取到临床诊断/ 主诉 / 现病史 / 既往史 / 病理诊断
        log.info("主数据接口地址: {}", interComment.getPathologyUrl());
        Map<String, Object> pathologyParams = new HashMap();
        // 目前custom15 是有前缀 zy01 的是 his_visit_id，^ 后的域id 是 his_domain_id
        // 目前custom19 是没有前缀 zy01 的是 his_id，^ 后的域id 是 his_visit_domain_id
        String[] custom15 = person.getCustom15().split(GlobalConstant.SPLIT_DOMAIN);
        String[] custom19 = person.getCustom19().split(GlobalConstant.SPLIT_DOMAIN);

        pathologyParams.put("his_id", StringUtils.isEmpty(recordComment.getHis_visit_id()) ? custom19[0] : recordComment.getHis_visit_id());
        pathologyParams.put("his_domain_id", StringUtils.isEmpty(recordComment.getHis_domain_id()) ? custom15[custom15.length - 1] : recordComment.getHis_domain_id());
        pathologyParams.put("his_visit_id", StringUtils.isEmpty(recordComment.getHis_id()) ? custom15[0] : recordComment.getHis_id());
        pathologyParams.put("his_visit_domain_id", StringUtils.isEmpty(recordComment.getHis_visit_domain_id()) ? custom19[custom19.length - 1] : recordComment.getHis_visit_domain_id());
        // 判断获取病例文书信息的时间区间
        // TODO 2018.12.27时间区间不添加了
//        int sectionDate = recordComment.getSectionDate();
//        if (Objects.isNull(sectionDate)) {
//            String startDate = recordComment.getStartDate();
//            String endDate = recordComment.getEndDate();
//            pathologyParams.put("start_date", startDate);
//            pathologyParams.put("end_date", endDate);
//            log.info("病历信息的开始时间为:{}.结束时间为:{}", startDate, endDate);
//        } else {
//            log.info("获取近: {} 天的病历时间.", sectionDate);
//            // 开始时间
//            String startDate = DateUtil.getBeforeTime(null, sectionDate);
//            String endDate = DateUtil.currentDate();
//            pathologyParams.put("start_date", startDate);
//            pathologyParams.put("end_date", endDate);
//            log.info("病历信息的开始时间为:{}.结束时间为:{}", startDate, endDate);
//        }
        log.info("主数据参数是: {}", JSONUtil.objectToJson(pathologyParams));
        return pathologyParams;
    }

    /**
     * 推送患者信息和病历信息
     *
     * @param url 接口地址
     * @param vo  推送对象
     */
    private ResponseBean doPush(String url, Object vo) {
        log.debug("接口地址：{}", url);
        log.info("接口地址：{}", url);
        JSONObject result = null;
        try {
            if (vo instanceof PatientInfoVo) {
                PatientInfoVo patientInfoVo = (PatientInfoVo) vo;
                result = restTemplate.postForObject(url, patientInfoVo, JSONObject.class);
            }
            if (vo instanceof PatientDocumentVo) {
                PatientDocumentVo patientDocumentVo = (PatientDocumentVo) vo;
                result = restTemplate.postForObject(url, patientDocumentVo, JSONObject.class);
            }
        } catch (RestClientException e) {
            log.error("推送失败!!! {},{}", e.getMessage(), e);
            return ResponseBean.error(e.getMessage());
        }
        if (!pushSuccess(result)) {
            return ResponseBean.error();
        }
        log.info("推送成功!!!");
        return ResponseBean.ok();
    }

    /**
     * 判断推送内容是否成功
     *
     * @param pushContent
     * @return
     */
    public boolean pushSuccess(JSONObject pushContent) {
        if (Objects.isNull(pushContent)) {
            log.info("推送失败.");
            return false;
        }
        if (pushContent.has(PushResultConstant.FAULT_CONTEXT)
                && StringUtils.isNotEmpty(pushContent.getString(PushResultConstant.FAULT_CONTEXT))) {
            log.error("推送失败.原因是: {}", pushContent.getString(PushResultConstant.FAULT_CONTEXT));
            return false;
        }
        return pushContent.getBoolean(PushResultConstant.IS_SUCCESS);
    }


}
